/** \file    MergeSegmentation.cpp
  * \brief   Operations combining several segments into one.
  * \date    2001 - 2003
  * \author  Fedor Chelnokov
  * \version $Header: /home/cscom1r4/cvsroot/cs/segm/src/MergeSegmentation.cpp,v 1.3 2005/04/04 04:10:16 cscom1r4 Exp $
  */

#include "segm/MergeSegmentation.h"
#include "segm/VecInd.h"
#include "xtd/kDimTree.h"
#include "imglib/segmcomb.h"
#include <algorithm>

struct merge_segm: public img::merge_patch<>
{
	double_point centre; //as always valid for roots only

	merge_segm() 
		{}
	merge_segm(const Segment &g) 
		{ pixels = g.pixelCount; 
		  centre = g.centre; }
	void subdue(merge_segm &child) {
		centre = 
			centre * pixels +
			child.centre * child.pixels;
		pixels += child.pixels; 
		centre /= pixels;
	}
};

void Segmentation::mergeSmall( int smallPcount, int /*targetPcount*/ )
{
	positions();
	std::vector<merge_segm> segm_arr(count());
	std::copy(segmentsBegin(), segmentsEnd(), segm_arr.begin()); ///< pixels copier

	size_t w = width(), h = height();

	VecIndTree tree;
	std::vector<VecInd> load(count());

	while(img::are_there_small_patch(segm_arr, smallPcount)) {
		size_t i;
		size_t rc = 0;
		//load centres of sets (roots) into tree
		for (i = 0; i != count(); ++i)
			if (segm_arr[i].is_root())
				load[rc++] = VecInd(segm_arr[i].centre, i);
		assert(rc > 0);
		tree.Create(&*load.begin(), rc);

		for (i = 0; i != count(); ++i) {
			if (!segm_arr[i].is_root() || segm_arr[i].pixels >= smallPcount) {
				segm_arr[i].merge_with = merge_segm::no_parent_value();
				continue;
			}

			const VecInd *n = tree.FindNearestPoint(VecInd(segm_arr[i].centre), DBL_MAX, true);
			if (n == 0) {
				///this situation should not be happen, however due to bugs in other modules it was happen
				assert(false);
				///this is to hide the problem in release versions
				goto error;
			}
			assert(i != n->ind);
			segm_arr[i].merge_with = n->ind;
		}

		img::do_merge_with(segm_arr, smallPcount);
	}

error:

	/* merge with biggest neighbor: result is far from excellence
	img::vmerge_small(
		img::uniform_raster<int>(0, w, h), //merges segments everywhere
		img::raster<int>(segmentCoordMap().begin(), w, h),
		segm_arr, 
		smallPcount);*/

	merge(segm_arr);
}
